package l1j.server.server.datatables;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.server.L1DatabaseFactory;
import l1j.server.server.GeneralThreadPool;
import l1j.server.server.IdFactory;
import l1j.server.server.model.L1MobGroupSpawn;
import l1j.server.server.model.L1Teleport;
import l1j.server.server.model.L1World;
import l1j.server.server.model.Instance.L1MonsterInstance;
import l1j.server.server.model.Instance.L1NpcInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.spawn.L1Spawn;
import l1j.server.server.utils.Random;
import l1j.server.server.utils.SQLUtil;
import l1j.server.server.utils.TimeUtil;
import l1j.server.server.utils.collections.Lists;

public class BossCycleTable extends Thread {

	private static Logger _log = Logger.getLogger(BossCycleTable.class
			.getName());

	public static void initilize() {
		GeneralThreadPool.getInstance().scheduleAtFixedRate(
				new BossCycleTable(), 0, 60 * 1000);
	}

	private final long _initialTime;

	private BossCycleTable() {
		_initialTime = System.currentTimeMillis();
		Connection con = null;
		PreparedStatement pstm = null;
		PreparedStatement pstm2 = null;
		ResultSet rs = null;
		ResultSet rs2 = null;
		try {
			con = L1DatabaseFactory.getInstance().getConnection();
			pstm = con
					.prepareStatement("SELECT * FROM x_boss_cycle where type = ?");
			pstm.setString(1, "assign");
			rs = pstm.executeQuery();
			while (rs.next()) {
				AssignBossCycle cycle = new AssignBossCycle();
				String[] time = rs.getString("time").split(":");
				int hour = Integer.parseInt(time[0]);
				int minute = Integer.parseInt(time[1]);
				int random = rs.getInt("random_range");
				minute += Random.nextInt(random * 2 + 1, -random);
				if (minute < 0) {
					minute += 60;
					hour -= 1;
				}
				if (hour < 0) {
					hour += 24;
				}
				cycle.name = rs.getString("type_name");
				cycle.hour = hour;
				cycle.minute = minute;
				_assignCycles.add(cycle);
			}

			pstm2 = con
					.prepareStatement("SELECT * FROM x_boss_cycle where type = ?");
			pstm2.setString(1, "cycle");
			rs2 = pstm2.executeQuery();
			while (rs2.next()) {
				GeneralBossCycle cycle = new GeneralBossCycle();
				cycle.name = rs2.getString("type_name");
				int cycleTime = Integer.parseInt(rs2.getString("time"));
				int random_range = rs2.getInt("random_range");
				int j = 0;
				cycle.cycleTimes = new int[(720 / cycleTime)];
				for (int i = cycleTime; i <= 720; i += cycleTime) { // 720 = 半天
																	// 不可能半天不重開吧0.0
					cycle.cycleTimes[j] = i
							+ Random.nextInt(random_range * 2 + 1,
									-random_range);
					j++;
				}
				_generalCycles.add(cycle);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			SQLUtil.close(rs);
			SQLUtil.close(rs2);
			SQLUtil.close(pstm);
			SQLUtil.close(pstm2);
			SQLUtil.close(con);
		}
		for (AssignBossCycle bossCycle : _assignCycles) {
			bossCycle.loadSpawndata();
		}
		for (GeneralBossCycle bossCycle : _generalCycles) {
			bossCycle.loadSpawndata();
		}

	}

	private List<AssignBossCycle> _assignCycles = Lists.newList();

	private List<GeneralBossCycle> _generalCycles = Lists.newList();

	public void run() {
		for (AssignBossCycle bossCycle : _assignCycles) {
			if (TimeUtil.Hour24() == bossCycle.hour
					&& TimeUtil.Minute() == bossCycle.minute) {
				bossCycle.spawnBoss();
				_assignCycles.remove(bossCycle);
			}
		}
		// 開機到現在過了幾分鐘
		int timeDiffMin = (int) ((System.currentTimeMillis() - this._initialTime) / 1000 / 60);
		for (GeneralBossCycle bossCycle : _generalCycles) {
			for (int i : bossCycle.cycleTimes) {
				if (i > timeDiffMin) {
					break;
				}
				if (i == timeDiffMin) {
					bossCycle.spawnBoss();
					break;
				}
			}
		}
	}

	class GeneralBossCycle {
		String name;
		int cycleTimes[];
		private List<BossSpawnData> _datas = Lists.newList();

		void loadSpawndata() {
			Connection con = null;
			PreparedStatement pstm = null;
			ResultSet rs = null;
			try {
				con = L1DatabaseFactory.getInstance().getConnection();
				pstm = con
						.prepareStatement("SELECT * FROM x_boss_born where cycle_type = ?");
				pstm.setString(1, name);
				rs = pstm.executeQuery();
				while (rs.next()) {
					BossSpawnData bsd = new BossSpawnData();
					bsd.npc_Id = rs.getInt("npc_Id");
					bsd.chance = rs.getInt("chance");
					bsd.group_id = rs.getInt("group_id");
					bsd.x = rs.getInt("x");
					bsd.y = rs.getInt("y");
					bsd.map = rs.getInt("map");
					bsd.count = rs.getInt("count");
					bsd.x1 = rs.getInt("x1");
					bsd.y1 = rs.getInt("y1");
					bsd.x2 = rs.getInt("x2");
					bsd.y2 = rs.getInt("y2");
					_datas.add(bsd);
				}
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				SQLUtil.close(rs);
				SQLUtil.close(pstm);
				SQLUtil.close(con);
			}
		}

		void spawnBoss() {
			for (BossSpawnData b : _datas) {
				try {
					if (!Random.chance100(b.chance)) {
						continue;
					}
					for (int i = 0; i < b.count; i++) {
						b.spawn();
					}
				} catch (Exception e) {
					_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
				}
			}
		}
	}

	class AssignBossCycle {
		String name;
		int hour;
		int minute;
		private List<BossSpawnData> _datas = Lists.newList();

		void loadSpawndata() {
			Connection con = null;
			PreparedStatement pstm = null;
			ResultSet rs = null;
			try {
				con = L1DatabaseFactory.getInstance().getConnection();
				pstm = con
						.prepareStatement("SELECT * FROM x_boss_born where cycle_type = ? and count > 0");
				pstm.setString(1, name);
				rs = pstm.executeQuery();
				while (rs.next()) {
					BossSpawnData bsd = new BossSpawnData();
					bsd.npc_Id = rs.getInt("npc_Id");
					bsd.chance = rs.getInt("chance");
					bsd.group_id = rs.getInt("group_id");
					bsd.x = rs.getInt("x");
					bsd.y = rs.getInt("y");
					bsd.map = rs.getInt("map");
					bsd.count = rs.getInt("count");
					bsd.x1 = rs.getInt("x1");
					bsd.y1 = rs.getInt("y1");
					bsd.x2 = rs.getInt("x2");
					bsd.y2 = rs.getInt("y2");
					bsd.rx = rs.getInt("random_x");
					bsd.ry = rs.getInt("random_y");
					_datas.add(bsd);
				}
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				SQLUtil.close(rs);
				SQLUtil.close(pstm);
				SQLUtil.close(con);
			}
		}

		void spawnBoss() {
			for (BossSpawnData b : _datas) {
				try {
					if (!Random.chance100(b.chance)) {
						continue;
					}
					for (int i = 0; i < b.count; i++) {
						b.spawn();
					}
				} catch (Exception e) {
					_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
				}
			}
		}
	}

	class BossSpawnData {
		int npc_Id;
		int chance;
		int group_id;
		int x, y, map;
		int count;
		int x1, y1, x2, y2;
		int rx, ry;

		void spawn() throws Exception {
			L1NpcInstance npc = NpcTable.getInstance().newNpcInstance(npc_Id);
			npc.setId(IdFactory.getInstance().nextId());
			npc.setHeading(0);
			npc.setMovementDistance(0);
			npc.setMap((short) map);

			int tryCount = 0;
			int newX = x, newY = y;
			while (tryCount <= 50) {
				if (x1 != 0 && x2 != 0 && y1 != 0 && y2 != 0) { // 指定範圍出生
					int rangeX = x2 - x1;
					int rangeY = y2 - y1;
					newX = Random.nextInt(rangeX) + x1;
					newY = Random.nextInt(rangeY) + y1;
					if (tryCount > 49) {
						newX = x;
						newY = y;
					}
				} else if (rx != 0 || ry != 0) {
					newX = (x + (Random.nextInt(rx) - Random.nextInt(rx)));
					newY = (y + (Random.nextInt(ry) - Random.nextInt(ry)));
				} else {
					newX = x;
					newY = y;
				}
				npc.setX(newX);
				npc.setY(newY);
				npc.setHomeX(x);
				npc.setHomeY(y);
				if (npc.getMap().isInMap(npc.getLocation())
						&& npc.getMap().isPassable(npc.getLocation())) {
					break;
				}
				tryCount++;
			}

			if (npc instanceof L1MonsterInstance) {
				L1MonsterInstance mon = (L1MonsterInstance) npc;
				mon.setIsBoss(true);
				mon.initHide();
				if (mon.getMapId() == 666) {
					mon.set_storeDroped(true);
				}
			}

			if ((npc_Id == 45573) && (map == 2)) { // バフォメット
				for (L1PcInstance pc : L1World.getInstance().getAllPlayers()) {
					if (pc.getMapId() == 2) {
						L1Teleport.teleport(pc, 32664, 32797, (short) 2, 0,
								true);
					}
				}
			}

			if (((npc_Id == 46142) && (map == 73))
					|| ((npc_Id == 46141) && (map == 74))) {
				for (L1PcInstance pc : L1World.getInstance().getAllPlayers()) {
					if ((pc.getMapId() >= 72) && (pc.getMapId() <= 74)) {
						L1Teleport.teleport(pc, 32840, 32833, (short) 72,
								pc.getHeading(), true);
					}
				}
			}
			if ((npc_Id == 81341)
					&& ((map == 2000) || (map == 2001) || (map == 2002) || (map == 2003))) { // 再生之祭壇
				for (L1PcInstance pc : L1World.getInstance().getAllPlayers()) {
					if ((pc.getMapId() >= 2000) && (pc.getMapId() <= 2003)) {
						L1Teleport.teleport(pc, 32933, 32988, (short) 410, 5,
								true);
					}
				}
			}

			L1Spawn.doCrystalCave(npc_Id);

			L1World.getInstance().storeObject(npc);
			L1World.getInstance().addVisibleObject(npc);

			if (npc instanceof L1MonsterInstance) {
				L1MonsterInstance mobtemp = (L1MonsterInstance) npc;
				if (mobtemp.getHiddenStatus() == 0) {
					mobtemp.onNpcAI(); // モンスターのＡＩを開始
				}
			}
			if (group_id != 0) {
				L1MobGroupSpawn.getInstance().doSpawn(npc, group_id, true,
						false);
			}
			npc.turnOnOffLight();
			npc.startChat(L1NpcInstance.CHAT_TIMING_APPEARANCE); // チャット開始

		}
	}
}
